﻿using DotNetOpenAuth;
using DotNetOpenAuth.AspNet.Clients;
using DotNetOpenAuth.Messaging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Runtime.Serialization.Json;

namespace SocialASP.Models
{
    public sealed class MyFacebookClient : OAuth2Client
    {
        private readonly string appId;
        private readonly string appSecret;
        private const string AuthorizationEndpoint = "https://www.facebook.com/dialog/oauth";
        private const string TokenEndpoint = "https://graph.facebook.com/oauth/access_token";

        public MyFacebookClient(string appId, string appSecret)
            : base("facebook")
        {
            this.appId = appId;
            this.appSecret = appSecret;
        }

        protected override Uri GetServiceLoginUrl(Uri returnUrl)
        {
            UriBuilder builder = new UriBuilder("https://www.facebook.com/dialog/oauth");
            Dictionary<string, string> dictionary = new Dictionary<string, string>();
            MessagingUtilities.AppendQueryArgument(builder, "client_id", appId);
            MessagingUtilities.AppendQueryArgument(builder, "redirect_uri", returnUrl.AbsoluteUri);
            MessagingUtilities.AppendQueryArgument(builder, "scope", "email");
            return builder.Uri;
        }

        public static T Deserialize<T>(Stream stream) where T : class
        {
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
            return (T)serializer.ReadObject(stream);
        }

        protected override IDictionary<string, string> GetUserData(string accessToken)
        {
            FacebookGraphData data;
            using (WebResponse response = WebRequest.Create("https://graph.facebook.com/me?access_token=" + EscapeUriDataStringRfc3986(accessToken)).GetResponse())
            {
                using (Stream stream = response.GetResponseStream())
                {
                    data = Deserialize<FacebookGraphData>(stream);
                }
            }
            Dictionary<string, string> dictionary = new Dictionary<string, string>();
            dictionary.Add("id", data.Id);
            dictionary.Add("username", data.Email);
            dictionary.Add("name", data.Name);
            dictionary.Add("link", (data.Link == null) ? null : data.Link.AbsoluteUri);
            dictionary.Add("gender", data.Gender);
            dictionary.Add("birthday", data.Birthday);
            return dictionary;
        }
        private static readonly string[] UriRfc3986CharsToEscape = new string[] { "!", "*", "'", "(", ")" };
        internal static string EscapeUriDataStringRfc3986(string value)
        {
            StringBuilder builder = new StringBuilder(Uri.EscapeDataString(value));
            for (int i = 0; i < UriRfc3986CharsToEscape.Length; i = (int)(i + 1))
            {
                builder.Replace(UriRfc3986CharsToEscape[i], Uri.HexEscape(UriRfc3986CharsToEscape[i][0]));
            }
            return builder.ToString();
        }

        private static string NormalizeHexEncoding(string url)
        {
            char[] chArray = url.ToCharArray();
            for (int i = 0; i < (chArray.Length - 2); i++)
            {
                if (chArray[i] == '%')
                {
                    chArray[i + 1] = char.ToUpperInvariant(chArray[i + 1]);
                    chArray[i + 2] = char.ToUpperInvariant(chArray[i + 2]);
                    i += 2;
                }
            }
            return new string(chArray);
        }

        protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
        {
            UriBuilder builder = new UriBuilder("https://graph.facebook.com/oauth/access_token");
            MessagingUtilities.AppendQueryArgument(builder, "client_id", this.appId);
            MessagingUtilities.AppendQueryArgument(builder, "redirect_uri", NormalizeHexEncoding(returnUrl.AbsoluteUri));
            MessagingUtilities.AppendQueryArgument(builder, "client_secret", this.appSecret);
            MessagingUtilities.AppendQueryArgument(builder, "code", authorizationCode);
            using (WebClient client = new WebClient())
            {
                string str = client.DownloadString(builder.Uri);
                if (string.IsNullOrEmpty(str))
                {
                    return null;
                }
                return HttpUtility.ParseQueryString(str)["access_token"];
            }
        }
    }
}